package com.blockmeta.bbs.immodule.service;

import com.blankj.utilcode.util.LogUtils;

import com.blockmeta.bbs.baselibrary.net.callback.BaseResponseCallBack;
import com.blockmeta.bbs.businesslibrary.util.AccountHelper;
import com.blockmeta.bbs.immodule.bean.JsonMessage;
import com.blockmeta.bbs.immodule.bean.MsgHelper;
import com.blockmeta.bbs.immodule.bean.Params;
import com.blockmeta.bbs.immodule.corebean.Impl.IMApplicationContext;
import com.blockmeta.bbs.immodule.dao.ChatMessage;
import com.blockmeta.bbs.immodule.dao.IMUserEntity;
import com.blockmeta.bbs.immodule.dao.Todo;
import com.blockmeta.bbs.immodule.utils.BroadcastHelper;
import com.google.gson.Gson;

import org.json.JSONObject;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import buf.Msg;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;

@Sharable
public class NettyClientHandler extends SimpleChannelInboundHandler<Msg.Message> {

    public NettyClientHandler(Session session, AtomicInteger pingTimes) {
        this.session = session;
        mPingTimes = pingTimes;
    }

    private Session session;
    private AtomicInteger mPingTimes;

    /**
     * 当出现WRITER_IDLE、ALL_IDLE时则需要向客户端发出ping消息，试探远端是否还在
     */
    private void sendPing(ChannelHandlerContext ctx) {
        LogUtils.i("authorkkk" + "im sendPing");
        Msg.Message ping = MsgHelper.newPingMessage(Msg.MessageType.CLIENT_PING,
                session.getUser().getUid() + session.getSessionToken());
        ctx.channel().writeAndFlush(ping);
        if (mPingTimes.get() > 5) {
            LogUtils.i("authorkkk" + "多次ping无响应：重连");
            session.setCurrentStatus(SocketStatus.DISCONNECTED);
            session.reConnect();
            mPingTimes.set(0);
        }
        mPingTimes.incrementAndGet();

    }

    //todo 存在同时触发多次的问题
    // 利用写空闲发送心跳检测消息
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt)
            throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent e = (IdleStateEvent) evt;
            switch (e.state()) {
                case WRITER_IDLE://写空闲
                    sendPing(ctx);
                    break;
                default:
                    break;
            }
        }
    }

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, Msg.Message baseMsg) throws Exception {
        switch (baseMsg.getMessageType()) {
            case CHAT_MESSAGE://在线聊天消息！

                LogUtils.i("author" + "-------------获取在线聊天信息---------------");
                LogUtils.i("author" + baseMsg.getChatMessage().getContent() + "fromid "
                        + baseMsg.getChatMessage().getFromId());
                LogUtils.i("author" + "--------------结束在线消息！-------------------");
                ChatMessage chatMessage = new ChatMessage();

                String content = baseMsg.getChatMessage().getContent();
                chatMessage.setContent(content);

                chatMessage.setDate((int) (System.currentTimeMillis() / 1000L));
                chatMessage.setFromId(baseMsg.getChatMessage().getFromId());
                chatMessage.setToId(baseMsg.getChatMessage().getToId());
                chatMessage.setType(ChatMessage.TYPE_RECEIVE);
                chatMessage.setWhoId(baseMsg.getChatMessage().getToId());
                chatMessage.setChecked(false);
                chatMessage.setMsgType(baseMsg.getChatMessage().getMsgType());
                chatMessage.setChatGroupId(baseMsg.getChatMessage()
                        .getChatGroupId());
                chatMessage.setContentType(baseMsg.getChatMessage()
                        .getContentType());
                chatMessage.setFilePath(baseMsg.getChatMessage().getFilePath());
                chatMessage.setChatMessageId(baseMsg.getChatMessage()
                        .getChatMessageId());
                chatMessage.setUuid(baseMsg.getChatMessage().getUuid());
                chatMessage.setStatus(baseMsg.getChatMessage().getStatus());

                // 附件消息
                chatMessage.setFileName(baseMsg.getChatMessage().getFileName());
                chatMessage.setFileType(baseMsg.getChatMessage().getFileType());
                chatMessage.setFileParam(baseMsg.getChatMessage().getFileParam());
                chatMessage.setUserAvator(baseMsg.getChatMessage().getUseravator());
                chatMessage.setUserName(baseMsg.getChatMessage().getUsername());
                chatMessage.setUserGroupId(baseMsg.getChatMessage().getUserGroupId());

                // 保存数据
                boolean addChatMessage = IMApplicationContext.getChatMessageDomainService().addChatMessage(chatMessage,
                        session.getUser().getUid());

                // 广播事件
                if (addChatMessage) {
                    BroadcastHelper.onReceiveLiveChatMessage(session, chatMessage);
                }
                break;
            case CHAT_MESSAGE_LIST://离线消息！  历史消息用于服务器漫游存储！
                // 历史消息
                List<Msg.ChatMessage> cmg = baseMsg.getChatMessageListMessageList();

                LogUtils.i("author" + "-------------离线聊天信息---------------条数" + cmg.size());
                long maxRecMsgId = 0;
                for (Msg.ChatMessage message : cmg) {
                    LogUtils.i("author" + message.getContent() + "fromid "
                            + message.getFromId());
                    if (message.getChatMessageId() > maxRecMsgId) {
                        maxRecMsgId = message.getChatMessageId();
                    }
                }
                LogUtils.i("author" + "sendDeleteUnliveMessage max id" + maxRecMsgId);
                if (cmg.size() > 0) {
                    session.sendDeleteUnliveMessage(maxRecMsgId);
                }

                if (cmg.size() < 1) {
                    BroadcastHelper.onReceiveChatMessageList(session);
                } else {
                    // 转发给JsonDataHandler处理
                    channelHandlerContext.fireChannelRead(cmg);
                }
                break;
            case CHAT_MESSAGE_LIST_HISTORY:
                //获取历史消息，只在用户同步云端记录的时候才用

                List<Msg.ChatMessage> hisMessages = baseMsg.getChatMessageListMessageList();

                channelHandlerContext.fireChannelRead(hisMessages);
                break;

            case FRIENDS_LIST://TODO 好友列表！
                List<Msg.Friends> fl = baseMsg.getFriendsListMessageList();
                LogUtils.i("author" + "FRIENDS_LIST socket return" + (fl != null ? fl.size() : 0));
                // 转发给FriendsListHandler处理

                if (fl == null || fl.size() == 0) {//空说明没有好友列表
                } else {//解析好友列表
                    channelHandlerContext.fireChannelRead(fl);
                }
                break;

            case JSON_DATA:
                JsonMessage jm = new JsonMessage();
                jm.setJsonMessageType(baseMsg.getJsonMessage().getJsonMessageType());
                jm.setJsonStr(baseMsg.getJsonMessage().getJsonStr());
                jm.setUserId(baseMsg.getJsonMessage().getUserId());

                // 转发给JsonDataHandler处理
                channelHandlerContext.fireChannelRead(jm);
                break;
            case TODO://获取在线TODO 数据
                Todo todo = new Todo();
                Msg.TodoMessage tm = baseMsg.getTodoMessage();
                LogUtils.i("author" + "在线TODO===" + baseMsg.getTodoMessage().toString());

                todo.setChecked(false);
                todo.setComplete(false);
                todo.setAgree(false);
                todo.setCreateDate((int) (System.currentTimeMillis() / 1000L));
                todo.setRequestMsg(tm.getRequestMsg());
                todo.setTodoId(tm.getTodoId());
                todo.setType(tm.getType());
                todo.setTodoSubject(tm.getTodoSubject());
                todo.setFromId(tm.getFromId());
                todo.setWhoId(Long.valueOf(session.getUser().getUid()));
                todo.setGroupId(tm.getGroupId());
                LogUtils.i("author" + "在线TODO：" + new Gson().toJson(todo));
                IMApplicationContext.getTodoDomainService()
                        .addTodo(todo);

                // 广播事件
                BroadcastHelper.onReceiveLiveTodo(session, todo);
                break;
            case TODO_MESSAGE_LIST://离线获取TODO 消息！List
                List<Msg.TodoMessage> tds = baseMsg.getTodoListMessageList();

                // 转发给FriendsGroupListHandler处理
                channelHandlerContext.fireChannelRead(tds);

                break;
            case CHAT_GROUP_LIST://圈子列表
                List<Msg.ChatGroup> tcs = baseMsg.getChatGroupListMessageList();
                LogUtils.i("author" + "CHAT_GROUP_LIST socket return" + (tcs != null ? tcs.size() : 0));
                // 转发给FriendsGroupListHandler处理
                channelHandlerContext.fireChannelRead(tcs);
                break;
            case SERVER_PONG:
                LogUtils.i("authorkkk" + "im心跳SERVER_PONG" + Thread.currentThread().getName());
                mPingTimes.set(0);
                break;
            case CLIENT_PONG:
                LogUtils.i("authorkkk" + "im心跳CLIENT_PONG" + Thread.currentThread().getName());
                mPingTimes.set(0);
                break;

            case FIEL://TODO  下载附件
                break;
            case RECEIPT:
                // 消息回执
                Msg.ReceiptMessage rm = baseMsg.getReceiptMessage();
                // 更新本地消息状态
                LogUtils.i("author" + "获取发送消息回执：" + rm.getUuid() + "回执状态：" + rm.getStatus());
                IMApplicationContext.getChatMessageDomainService().updateChatMessageStatus(
                        rm.getUuid(), rm.getStatus());
                // 通知UI组件更新界面
                BroadcastHelper.onReceiveReceiptMessage(session, rm.getUuid(), rm.getStatus());
                break;
            case LOGIN_SUCCESS:
                LogUtils.i("author" + "登陆服务器成功");
                //把所有以前的发送中状态的消息改成发送超时，因为可能在发送的时候app被杀掉
                IMApplicationContext.getChatMessageDomainService().updateMessageStatusToFail(AccountHelper.getUidInt());
                LogUtils.i("author" + "登陆服务器成功2");
                BroadcastHelper.onReceiveLoginMessage(session, true);
                LogUtils.i("author" + "登陆服务器成功3");
                break;
            case LOGIN_ERROR:
                LogUtils.i("author" + "登陆服务器失败");
                BroadcastHelper.onReceiveLoginMessage(session, false);
                break;
            case AUTH_ERROR:
                LogUtils.i("author" + "用户认证失败！登陆失败，需要处理异常！");
                session.auth();
                //TODO 登陆服务器失败错误处理！！！比如说发送消息之类的
                break;
            case SERVER_PING:
                LogUtils.i("author" + "心跳SERVER_PING" + Thread.currentThread().getName());
                mPingTimes.set(0);
                break;
            case NOTICE_MESSAGE:
                Msg.NoticeMessage noticeMessage = baseMsg.getNoticeMessage();
                if (noticeMessage == null) {
                    LogUtils.d("author" + "receive notice msg" + null);
                }
                if (noticeMessage.getData() == null) {
                    LogUtils.d("author" + "receive notice msg getdata" + null);
                }
                JSONObject jsonObject;
                jsonObject = new JSONObject(noticeMessage.getData());
                if (jsonObject != null) {
                    LogUtils.d("author" + "receive notice msg" + jsonObject.toString());
                    switch (noticeMessage.getNoticeType()) {
                        case Params.NOTICE_TYPE_ADDFRIEND:
                            IMApplicationContext.getUserDomainService().addFriend(jsonObject.getLong("user_id"),
                                    new BaseResponseCallBack<String, IMUserEntity>() {
                                        @Override
                                        public void fail(String msg) {

                                        }

                                        @Override
                                        public void success(IMUserEntity entity) {
                                            BroadcastHelper.sendFriendAddEvent(session);
                                        }
                                    });
                            break;
                        case Params.NOTICE_TYPE_DELETEFRIEND:
                            IMApplicationContext.getUserDomainService().deleteFriend(jsonObject.getLong("user_id"));
                            BroadcastHelper.sendFriendDeleteEvent(session);
                            break;
                        case Params.NOTICE_TYPE_DELETECIRCLE:
                            IMApplicationContext.getCircleDomainService().deleteCircle(jsonObject.getLong("group_id"));
                            BroadcastHelper.sendCircleDeleteEvent(session);
                            break;
                        case Params.NOTICE_TYPE_ADDCIRCLE:
                            IMApplicationContext.getCircleDomainService().addCircle(jsonObject.getLong("group_id"),
                                    new BaseResponseCallBack<String, IMUserEntity>() {
                                        @Override
                                        public void fail(String msg) {

                                        }

                                        @Override
                                        public void success(IMUserEntity entity) {
                                            BroadcastHelper.sendCircleAddEvent(session);
                                        }
                                    });
                            break;
                    }
                }

                break;
            default:
                break;
        }

        ReferenceCountUtil.release(baseMsg);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        //
        LogUtils.i("authorkkk" + "channelInactive Socket断了");
        session.setCurrentStatus(SocketStatus.DISCONNECTED);
        session.reConnect();
        LogUtils.i("authorkkk" + "异常重连");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        StackTraceElement[] stackTrace = cause.getCause().getStackTrace();
        if (stackTrace != null) {
            for (StackTraceElement element : stackTrace) {
                LogUtils.i("authorkkk" + "exceptionCaught " + element.toString());
            }
        }
        LogUtils.i("authorkkk" + "exceptionCaught 发生异常了" + cause.getMessage());
    }


}